﻿// Imports
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
using System.Web.Configuration;

namespace Nickel
{

    /// <summary>
    /// Handles uploads
    /// </summary>
    public class Upload : Page
    {

        /// <summary>
        /// Web.config
        /// </summary>
        HttpRuntimeSection config;

        /// <summary>
        /// Handles page load
        /// </summary>
        /// <param name="sender">Sender object</param>
        /// <param name="e">Event arguments</param>
        protected void Page_Load(object sender, EventArgs e)
        {

            try
            {

                // Get user
                Author user = Account.GetSignedInAuthor(Data, Request.Cookies[Settings.COOKIE_NAME]);

                // Must be admin
                if (user == null || !user.Admin)
                {

                    // Write error
                    Response.Write(Errors.ADMIN_REQUIRED);

                }
                else
                {

                    // Configure .NET
                    config = new HttpRuntimeSection();
                    config.Enable = true;
                    config.ShutdownTimeout = TimeSpan.FromMinutes(20);
                    config.ExecutionTimeout = TimeSpan.FromMinutes(20);
                    config.MaxRequestLength = 1000000;

                    // Count files
                    int fileCount = Request.Files.Count;

                    // No file uploaded
                    if (fileCount <= 0)
                    {

                        // Write error
                        Response.Write(Errors.NO_FILE);

                    }
                    else
                    {

                        // Declare return string
                        string strResult = "<div id=\"" + Constants.UPLOAD_FILE_LIST + "\">Uploaded file " + (fileCount > 1 ? "URLs" : "URL") + ":<br />";

                        // Iterate through files
                        for (int i = 0; i < fileCount; i++)
                        {

                            // Get file
                            HttpPostedFile file = Request.Files[i];

                            // Uploading profile photo
                            if (Settings.PROFILE_IMAGE_ENABLED && Request.Form["authorId"] != null)
                            {

                                // Must be an image
                                if (StringHelper.ValidFile(FilePatternType.IMAGE).IsMatch(file.FileName))
                                {

                                    // Create filename
                                    string strFileName = "profile/" + Request.Form["authorId"] + ".jpg";

                                    // Make small copy
                                    makeSmall(file, Settings.PROFILE_IMAGE_SIZE, strFileName, true);

                                    // Add filename to result list
                                    string strFileUrl = strBaseUrl + "uploads/" + strFileName;
                                    strResult = "<div id=\"" + Constants.UPLOAD_FILE_LIST + "\"><img src=\"" + strFileUrl + "\" />";

                                }
                                else
                                {

                                    // Write error
                                    strResult = "<div id=\"" + Constants.UPLOAD_FILE_LIST + "\">" + Errors.INVALID_FILE_TYPE;

                                }

                                // Only allow one photo
                                i = fileCount;

                            }
                            else
                            {

                                // Validate file
                                if (StringHelper.ValidFile(FilePatternType.ALL).IsMatch(file.FileName))
                                {

                                    // Save file
                                    file.SaveAs(Server.MapPath(@"~/uploads/" + file.FileName));

                                    // Add filename to result list
                                    string strFileUrl = strBaseUrl + "uploads/" + file.FileName;
                                    strResult += "<a href=\"" + strFileUrl + "\" target=\"_blank\" class=\"tiny\">" + strFileUrl + "</a>";

                                    // Create a thumbnail of images
                                    if (StringHelper.ValidFile(FilePatternType.IMAGE).IsMatch(file.FileName))
                                    {

                                        // Set filename
                                        string strFileName = file.FileName.Substring(0, file.FileName.LastIndexOf(".")) + "_sm.jpg";

                                        // Make small copy
                                        if (makeSmall(file, Settings.SMALL_IMAGE_SIZE, strFileName, false))
                                        {

                                            // Add file to list if copy was made
                                            strFileUrl = strBaseUrl + "uploads/" + strFileName;
                                            strResult += "<br /><a href=\"" + strFileUrl + "\" target=\"_blank\" class=\"tiny\">" + strFileUrl + "</a>";

                                        }

                                    }

                                }
                                else
                                {

                                    // Write error
                                    strResult = "<div id=\"" + Constants.UPLOAD_FILE_LIST + "\">" + Errors.INVALID_FILE_TYPE;

                                }

                            }

                            // Add line break
                            if (i < fileCount - 1) strResult += "<br />";

                        }

                        // Write response
                        Response.Write(strResult + "</div>");

                    }

                }

                // Clean up
                user = null;

            }
            catch (Exception ex)
            {

                // Write error
                Response.Write("<div id=\"" + Constants.UPLOAD_FILE_LIST + "\">" + ex.Message + "</div>");

            }

        }

        /// <summary>
        /// Saves the uploaded file as a smaller image
        /// </summary>
        /// <param name="file">Incoming file</param>
        /// <param name="maxSize">Max width/height</param>
        /// <param name="filename">New filename</param>
        private bool makeSmall(HttpPostedFile file, int maxSize, string filename, bool crop)
        {

            // Declare return string
            string strFileName = string.Empty;

            // Get the source image
            Image input = System.Drawing.Image.FromStream(file.InputStream);

            // Get size
            int height = input.Height;
            int width = input.Width;

            // Image needs resize
            if (width > maxSize || height > maxSize)
            {

                // Check aspect
                if (width > height)
                {

                    // Get new size
                    height = (int)(((float)maxSize / (float)width) * (float)height);
                    width = maxSize;

                }
                else
                {

                    // Get new size
                    width = (int)(((float)maxSize / (float)height) * (float)width);
                    height = maxSize;

                }

                // Define destination, size, and source rectangles
                Rectangle rectDest;
                Rectangle rectSize;
                Rectangle rectSource = new Rectangle(0, 0, input.Width, input.Height);

                // Cropping
                if (crop)
                {

                    // Declare scale
                    double cropScale;

                    // Wide
                    if (width >= height)
                    {

                        // Scale
                        cropScale = (double)width / (double)height;
                        height = (int)((double)height * cropScale);
                        width = (int)((double)width * cropScale);

                        // Define destination and size rectangles
                        rectDest = new Rectangle(0, 0, width, height);
                        rectSize = new Rectangle(0, 0, height, height);

                    }
                    else
                    {

                        // Scale
                        cropScale = (double)height / (double)width;
                        height = (int)((double)height * cropScale);
                        width = (int)((double)width * cropScale);

                        // Define destination and size rectangles
                        rectDest = new Rectangle(0, 0, width, height);
                        rectSize = new Rectangle(0, 0, width, width);

                    }

                }
                else
                {

                    // Define destination and size rectangles
                    rectDest = new Rectangle(0, 0, width, height);
                    rectSize = new Rectangle(0, 0, width, height);

                }

                // Set up JPEG encoding
                Encoder encoder = Encoder.Quality;
                EncoderParameter ratio = new EncoderParameter(encoder, 100L);
                EncoderParameters parameters = new EncoderParameters(1);
                parameters.Param[0] = ratio;
                ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();

                // Set scale
                double scale = rectSource.Width >= rectSource.Height ? (double)rectSize.Width / (double)rectSource.Width : (double)rectSize.Height / (double)rectSource.Height;

                // Set destination
                rectDest.Height = (int)((double)rectSource.Height * scale);
                rectDest.Width = (int)((double)rectSource.Width * scale);
                rectDest.X = (int)((double)(rectSize.Width - rectDest.Width) * 0.5);
                rectDest.Y = (int)((double)(rectSize.Height - rectDest.Height) * 0.5);

                // Set up the output image
                Bitmap output = new Bitmap(rectSize.Width, rectSize.Height, PixelFormat.Format24bppRgb);
                output.SetResolution(input.HorizontalResolution, input.VerticalResolution);

                // Create a graphics object from the blank bitmap
                Graphics graphics = Graphics.FromImage(output);

                // Super smoove anti-aliasing settings
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
                graphics.CompositingQuality = CompositingQuality.HighQuality;

                // Draw the image
                graphics.DrawImage(input, rectDest, rectSource, GraphicsUnit.Pixel);

                // Write image to disk
                output.Save(Server.MapPath(@"~/uploads/" + filename), encoders[1], parameters);

                // Clean up
                graphics.Dispose();
                input.Dispose();
                output.Dispose();
                parameters.Dispose();
                ratio.Dispose();

                // Image resized
                return true;

            } 

            // Return false if no resize
            return false;

        }

    }

}
